闲话 22.10.3
闲话
最近有一件事我比较在意。
某一日 EI 发了一个犇犇
众所周知,这是《四重罪孽》里的一句歌词
然后某些中V厨就按耐不住自己手头的歌词了
回想初二在家的那段时间
一套作业
带上耳机循环一天《妄想症》
的时光
让我现在还能唱一点四重罪孽
但是现在早就不记得词曲了 下次回家听听吧
夢の続きを知りたいのかい?
誰も見たこと無い絵本を
捲りなさい
それがあなたの
望む世界だとしよう
夢の終わりで眠ればいい
杂题
称一个长度为 的序列 是 的,当且仅当对于任意 ,满足 ,其中
|
表示按位或运算。称一个长度为 的序列 是 的,当且仅当它可以重排成一个 的序列。给你 ,求长度为 ,每个元素值域为 的序列中有多少个是 的,对 取模。
。
读题。读完了可以发现合法序列是关于中心对称的。具体地,从两边开始分别向中间镜像地拓展一个数,每次加入的二进制位是相同的。
然后刻画一下这个性质:
首先整一个计数器 。每次选择这个序列两端的数 ,一定满足 。赋 ,再把这两个数从序列中删除。
由于需要计数的串是重排之后的,因此对于 的序列,可以通过若干次操作变为长度不超过 1 的序列:
仍然是初始为 0 的计数器,每次选择一对任意位置的数 满足 ,赋 ,随后把这两个数删除。
对于不 的序列,定义它的最优子序列为通过上述操作移除的序列。可以发现在移除最优子序列后,不 的序列剩余元素都满足 xor 不为 0 且之间两两不同。
因此一个不 的序列能够生成一个长度小于它的 的序列。
考虑一个套路容斥。
表示长度为 ,二进制位数量为 的序列数, 表示长度为 ,二进制位数量为 的不合法序列数, 表示长度为 ,二进制位数量为 ,内部元素均不为 0 且两两不同的序列数。
由定义,可以得到 的计算方式:
的计算式也可类似地得到:
然后可以枚举最优子序列长度和二进制位个数来得到 。
意义:我们首先钦定最优子序列的长度 和位数 ,这部分的总种类数是 的。对于长度为 的每个剩余元素,能任意填入最优子序列中已经存在的 位,这部分的总种类数是 的。由于剩余元素都满足 xor 不为 0 且之间两两不同,这部分的种类数是 的。最后考虑最优子序列的种类数,为 。求积再求和即为上式。
然后递推就完了。
总时间复杂度 。
code
#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for (register int (i) = (a); (i) <= (b); ++(i))
#define pre(i,a,b) for (register int (i) = (a); (i) >= (b); --(i))
const int N = 90 + 10;
int n, k, mod, pw[N * N], C[N][N], f[N][N], g[N][N], h[N][N], ans;
typedef long long ll; typedef __int128 lll;
struct FastMod { int m; ll b; void init(int _m) { m = _m; b = ((lll)1<<64) / m; } int operator() (ll a) {ll q = ((lll)a * b) >> 64; a -= q * m; if (a >= m) a -= m; return a; } } Mod;
int add(int a, int b) { return (a += b) >= mod ? a - mod : a; }
int mul(int a, int b) { return Mod(1ll * a * b); } template <typename ...Args> int mul(int a, Args ...b) { return mul(a, mul(b...)); }
int L(int n, int m) { int ret = 1; rep(i,0,m-1) ret = mul(ret, n - i + mod); return ret; }
void init(int bnd) {
Mod.init(mod);
rep(i,0,bnd) C[i][0] = 1;
pw[0] = 1;
rep(i,1,bnd) {
rep(j,1,i) C[i][j] = add(C[i-1][j-1], C[i-1][j]);
}
rep(i,1,n*k) pw[i] = add(pw[i-1], pw[i-1]);
}
signed main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
cin >> n >> k >> mod;
init(max(n, k));
rep(i,0,n) rep(j,0,k) rep(l,0,j) {
f[i][j] = add(f[i][j], mul(((j - l) & 1) ? mod - C[j][l] : C[j][l], pw[l * i]));
h[i][j] = add(h[i][j], mul(((j - l) & 1) ? mod - C[j][l] : C[j][l], L(pw[l] - 1, i)));
}
rep(i,1,n) rep(j,1,k) rep(i2,0,i-1) rep(j2,0,j-1)
if ((n & 1) and (i == n) and (i2 == n-1)) continue;
else g[i][j] = add(g[i][j], mul(C[i][i2], C[j][j2], pw[j2 * (i - i2)], h[i - i2][j - j2], f[i2][j2] + mod - g[i2][j2]));
rep(i,0,k) ans = add(ans, mul(C[k][i], f[n][i] + mod - g[n][i]));
cout << ans << endl;
}
以下是博客签名,与正文无关。
请按如下方式引用此页:
本文作者 joke3579,原文链接:https://www.cnblogs.com/joke3579/p/chitchat221003.html。
遵循 CC BY-NC-SA 4.0 协议。
请读者尽量不要在评论区发布与博客内文完全无关的评论,视情况可能删除。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)